package com.scau.os.fileSystem.directory;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.scau.os.fileSystem.memory.Disk;
import com.scau.os.fileSystem.memory.FAT;

public class Directory extends DirectoryEntry {

    public Directory(String path, Property property) {
        super(path, property);
    }

    public Directory(String path) throws Exception {
        super(path);
    }

    public static void initDirectoryEntry(int block) throws Exception {
        byte[] entries = Disk.INSTANCE.readBlock(block);
        for (int i = 0; i < entries.length; i += DIRECTORY_ENTRY_LENGTH) {
            System.arraycopy(EMPTY_DIRECTORY_ENTRY.property.toBytes(), 0, entries, i, DIRECTORY_ENTRY_LENGTH);
        }
        Disk.INSTANCE.writeBlock(block, entries);
    }

    public int getBlockOfEntry(DirectoryEntry targetDirectoryEntry) throws Exception {
        List<Integer> blocks = getBlocks();
        for (int block : blocks) {
            byte[] entries = Disk.INSTANCE.readBlock(block);
            for (int i = 0; i < entries.length; i += DIRECTORY_ENTRY_LENGTH) {
                byte[] entry = Arrays.copyOfRange(entries, i, i + DIRECTORY_ENTRY_LENGTH);
                Property property = new Property(entry);
                DirectoryEntry directoryEntry = new DirectoryEntry(
                        this.path.getAbsolutePath() + "/" + property.getName(), property);

                if (directoryEntry.equals(targetDirectoryEntry) == true) {
                    return block;
                }
            }
        }
        return 0;
    }

    public boolean exist(DirectoryEntry directoryEntry) throws Exception {
        List<DirectoryEntry> children = getChildren();
        for (DirectoryEntry child : children) {
            if (child.equals(directoryEntry) == true) {
                return true;
            }
        }
        return false;
    }

    public int getAvailableBlock() throws Exception {
        List<Integer> blocks = getBlocks();
        for (int block : blocks) {
            byte[] entries = Disk.INSTANCE.readBlock(block);
            for (int i = 0; i < entries.length; i += DIRECTORY_ENTRY_LENGTH) {
                byte[] entry = Arrays.copyOfRange(entries, i, i + DIRECTORY_ENTRY_LENGTH);
                Property property = new Property(entry);
                DirectoryEntry directoryEntry = new DirectoryEntry(
                        this.path.getAbsolutePath() + "/" + property.getName(), property);

                if (directoryEntry.equals(EMPTY_DIRECTORY_ENTRY) == true) {
                    return block;
                }
            }
        }

        int newBlock = FAT.INSTANCE.allocateBlock();
        FAT.INSTANCE.setFATItem(blocks.get(blocks.size() - 1), newBlock);

        initDirectoryEntry(newBlock);
        return newBlock;
    }

    public List<DirectoryEntry> getChildren() throws Exception {
        List<DirectoryEntry> children = new ArrayList<>();
        List<Integer> blocks = getBlocks();
        for (int block : blocks) {
            byte[] entries = Disk.INSTANCE.readBlock(block);
            for (int i = 0; i < entries.length; i += DIRECTORY_ENTRY_LENGTH) {
                byte[] entry = Arrays.copyOfRange(entries, i, i + DIRECTORY_ENTRY_LENGTH);
                Property property = new Property(entry);

                DirectoryEntry directoryEntry = new DirectoryEntry(
                        this.path.getAbsolutePath() + "/" + property.getName(), property);
                if(directoryEntry.isFile()){
                    directoryEntry.getPath().setAbsolutePath(this.path.getAbsolutePath() + "/" + property.getName()+'.'+property.getType());
                }

                if (directoryEntry.equals(EMPTY_DIRECTORY_ENTRY) == false) {
                    children.add(directoryEntry);
                }
            }
        }
        return children;
    }

    public boolean isEmpty() throws Exception {
        return getChildren().isEmpty();
    }

    public List<File> getAllFiles() throws Exception {
        List<File> files = new ArrayList<>();
        List<DirectoryEntry> children = getChildren();
        for (DirectoryEntry child : children) {
            if (child.isFile()) {
                files.add(new File(child.path.getAbsolutePath(), child.property));
            }
        }
        return files;
    }

    public List<Directory> getAllDirectories() throws Exception {
        List<Directory> directories = new ArrayList<>();
        List<DirectoryEntry> children = getChildren();
        for (DirectoryEntry child : children) {
            if (child.isDirectory()) {
                directories.add(new Directory(child.path.getAbsolutePath(), child.property));
            }
        }
        return directories;
    }

}